home *** CD-ROM | disk | FTP | other *** search
- /*******************************************************************************
- * Line plane sweep algorithm implementation - actual code. *
- * *
- * Written by: Gershon Elber Ver 1.0, June 1993 *
- *******************************************************************************/
-
- #include <stdio.h>
- #include <math.h>
- #include "irit_sm.h"
- #include "imalloc.h"
- #include "ln_sweep.h"
-
- #define LS_XBBOX_OVERLAP(L1, L2) (L1 -> _MaxVals[0] > L2 -> _MinVals[0] && \
- L2 -> _MaxVals[0] > L1 -> _MinVals[0])
-
- #if defined(ultrix) && defined(mips)
- static int LsSortCompare(VoidPtr Ptr1, VoidPtr Ptr2);
- #else
- static int LsSortCompare(const VoidPtr Ptr1, const VoidPtr Ptr2);
- #endif /* ultrix && mips (no const support) */
-
- static void LsInitialize(LsLineSegStruct **Lines);
- static void LsIntersect(LsLineSegStruct *Lines);
- static int LsIntersectOne(LsLineSegStruct *L1, LsLineSegStruct *L2,
- RealType *t1, RealType *t2);
-
- /*******************************************************************************
- * Invokes the right functions in the right order... *
- * The Lines segments are updated so the Inters slot holds the list of *
- * intersections with the other segments, NULL if none. *
- * Returned list might be in different order than that is given. *
- *******************************************************************************/
- void LineSweep(LsLineSegStruct **Lines)
- {
- if (Lines == NULL || *Lines == NULL)
- return;
-
- LsInitialize(Lines);
- LsIntersect(*Lines);
- }
-
- /*******************************************************************************
- * Compare two LsLineSegStructs with according to _MinVals[1]. *
- *******************************************************************************/
- #if defined(ultrix) && defined(mips)
- static int LsSortCompare(VoidPtr Ptr1, VoidPtr Ptr2)
- #else
- static int LsSortCompare(const VoidPtr Ptr1, const VoidPtr Ptr2)
- #endif /* ultrix && mips (no const support) */
- {
- RealType
- Diff = ((*(LsLineSegStruct **) Ptr1)) -> _MinVals[1] -
- ((*(LsLineSegStruct **) Ptr2)) -> _MinVals[1];
-
- return SIGN(Diff);
- }
-
- /*******************************************************************************
- * Initialize the data structures for the plane sweep. *
- *******************************************************************************/
- static void LsInitialize(LsLineSegStruct **Lines)
- {
- int i;
- LsLineSegStruct *Line, **LineArray, **l;
-
- for (i = 0, Line = *Lines; Line != NULL; Line = Line -> Pnext, i++) {
- RealType Size;
-
- Line -> _MinVals[0] = MIN(Line -> Pts[0][0], Line -> Pts[1][0]);
- Line -> _MinVals[1] = MIN(Line -> Pts[0][1], Line -> Pts[1][1]);
- Line -> _MaxVals[0] = MAX(Line -> Pts[0][0], Line -> Pts[1][0]);
- Line -> _MaxVals[1] = MAX(Line -> Pts[0][1], Line -> Pts[1][1]);
-
- /* Computes the vector from first point to second. */
- Line -> _Vec[0] = Line -> Pts[1][0] - Line -> Pts[0][0];
- Line -> _Vec[1] = Line -> Pts[1][1] - Line -> Pts[0][1];
-
- /* Computes the line equation for the segment as Ax + By + C = 0, */
- /* sqrt(A^2 + B^2) = 1. */
- Line -> _ABC[0] = Line -> _Vec[1];
- Line -> _ABC[1] = -Line -> _Vec[0];
- Size = sqrt(SQR(Line -> _ABC[0]) + SQR(Line -> _ABC[1]));
- if (Size > 0.0) {
- Line -> _ABC[0] /= Size;
- Line -> _ABC[1] /= Size;
- Line -> _ABC[2] = -(Line -> _ABC[0] * Line -> Pts[0][0] +
- Line -> _ABC[1] * Line -> Pts[0][1]);
- }
- else {
- /* Zero length segment. Sets the line equation to never yield an */
- /* intersection. */
- Line -> _ABC[0] = Line -> _ABC[1] = 0.0;
- Line -> _ABC[2] = 1.0;
- }
-
- Line -> Inters = NULL;
- }
-
- LineArray = (LsLineSegStruct **) IritMalloc(sizeof(LsLineSegStruct *) * i);
- for (Line = *Lines, l = LineArray; Line != NULL; Line = Line -> Pnext)
- *l++ = Line;
- qsort(LineArray, i, sizeof(LsLineSegStruct *), LsSortCompare);
- *Lines = *LineArray;
- for (l = LineArray; --i; l++)
- l[0] -> Pnext = l[1];
- l[0] -> Pnext = NULL;
- IritFree((VoidPtr) LineArray);
- }
-
- /*******************************************************************************
- * The actual intersections. Not a real plane sweep, but close... *
- * March along the given list and intersect every line with all lines in the *
- * domain that can affect it. *
- *******************************************************************************/
- static void LsIntersect(LsLineSegStruct *Lines)
- {
- static int
- IdNumber = 0;
- LsLineSegStruct *Line, *Line2;
-
- for (Line = Lines; Line -> Pnext != NULL; Line = Line -> Pnext) {
- RealType t, t2,
- MaxY = Line -> _MaxVals[1];
-
- for (Line2 = Line -> Pnext; Line2 != NULL; Line2 = Line2 -> Pnext) {
- if (Line2 -> _MinVals[1] > MaxY)
- break; /* Cannot intersect any more */
-
- if (Line -> Id != Line2 -> Id &&
- LS_XBBOX_OVERLAP(Line, Line2) &&
- LsIntersectOne(Line, Line2, &t, &t2)) {
- LsIntersectStruct
- *Inter = (LsIntersectStruct *)
- IritMalloc(sizeof(LsIntersectStruct)),
- *Inter2 = (LsIntersectStruct *)
- IritMalloc(sizeof(LsIntersectStruct));
-
- Inter -> t = t;
- Inter -> OtherT = t2;
- Inter -> OtherSeg = Line2;
- Inter -> Id = IdNumber;
- Inter -> Pnext = Line -> Inters;
- Line -> Inters = Inter;
-
- Inter2 -> t = t2;
- Inter2 -> OtherT = t;
- Inter2 -> OtherSeg = Line;
- Inter2 -> Id = IdNumber++;
- Inter2 -> Pnext = Line2 -> Inters;
- Line2 -> Inters = Inter2;
- }
- }
- }
- }
-
- /*******************************************************************************
- * Computes a single intersection between two line segments. *
- * Returns TRUE if found an intersection and sets t1/t2 to the parameter *
- * values of the intersection (t == 0 for first point, t == 1 for second). *
- *******************************************************************************/
- static int LsIntersectOne(LsLineSegStruct *L1, LsLineSegStruct *L2,
- RealType *t1, RealType *t2)
- {
- RealType Dist11, Dist12, Dist21, Dist22, XDiff, YDiff, Det;
-
- Dist11 = L1 -> _ABC[0] * L2 -> Pts[0][0] +
- L1 -> _ABC[1] * L2 -> Pts[0][1] +
- L1 -> _ABC[2];
- Dist12 = L1 -> _ABC[0] * L2 -> Pts[1][0] +
- L1 -> _ABC[1] * L2 -> Pts[1][1] +
- L1 -> _ABC[2];
- if (Dist11 * Dist12 > 0.0) /* L2's two end points are on same size of L1. */
- return FALSE;
-
- Dist21 = L2 -> _ABC[0] * L1 -> Pts[0][0] +
- L2 -> _ABC[1] * L1 -> Pts[0][1] +
- L2 -> _ABC[2];
- Dist22 = L2 -> _ABC[0] * L1 -> Pts[1][0] +
- L2 -> _ABC[1] * L1 -> Pts[1][1] +
- L2 -> _ABC[2];
- if (Dist21 * Dist22 > 0.0) /* L1's two end points are on same size of L2. */
- return FALSE;
-
- /* Solve the following linear system for t1 and t2. */
- /* */
- /* L1X1 + t1 L1Vx = L2X1 + t2 L2Vx */
- /* L1Y1 + t1 L1Vy = L2Y1 + t2 L2Vy */
- /* */
- /* or, */
- /* */
- /* t1 L1Vx - t2 L2Vx = L2X1 - L1X1 */
- /* t1 L1Vy - t2 L2Vy = L2Y1 - L1Y1 */
- /* */
- Det = L1 -> _Vec[1] * L2 -> _Vec[0] - L1 -> _Vec[0] * L2 -> _Vec[1];
- if (Det == 0.0)
- return FALSE;
-
- XDiff = L2 -> Pts[0][0] - L1 -> Pts[0][0];
- YDiff = L2 -> Pts[0][1] - L1 -> Pts[0][1];
-
- *t1 = (YDiff * L2 -> _Vec[0] - XDiff * L2 -> _Vec[1]) / Det;
- *t2 = (L1 -> _Vec[0] * YDiff - L1 -> _Vec[1] * XDiff) / Det;
-
- return *t1 > 0.0 && *t1 <= 1.0 && *t2 > 0.0 && *t2 <= 1.0;
- }
-